package com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.global;

import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.data.variable;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.BaseJSFunction;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.UnexpectedObjectTypeError;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.UnknownOperationError;

public interface BaseJSConstants {
	static final Object UNDEFINED = new Object() {
		@Override
		public String toString() {
			return "undefined";
		}
	};

	public static void copyArguments(final String[] args, final Object[] output) {
		copyArguments(args, output, null);
	}

	public static enum InternalArgCopyAction {
		ITERATE,
		BREAK,
		CONTINUE
	}

	public static InternalArgCopyAction internalArgCopy(String arg, final int i, final variable<Boolean> IS_ENCLOSED_ARRAY, final String[] args,
			final Object[] output, final BaseJSFunction function) {
		while (arg.startsWith(" "))
			arg = arg.substring(1);
		if (arg.isEmpty())
			return InternalArgCopyAction.CONTINUE;
		if (StringsUtil.isNumber(arg)) {
			output[i] = Double.parseDouble(arg);
			return InternalArgCopyAction.ITERATE;
		} else if (StringsUtil.isString(arg)) {
			output[i] = StringsUtil.substringBetweenO(arg, "\"", "\"");
			return InternalArgCopyAction.ITERATE;
		} else if (arg.equals("true")) {
			output[i] = true;
			return InternalArgCopyAction.ITERATE;
		} else if (arg.equals("false")) {
			output[i] = false;
			return InternalArgCopyAction.ITERATE;
		} else if (function != null && function.valueCache.containsKey(arg)) {
			output[i] = function.valueCache.get(arg);
			return InternalArgCopyAction.ITERATE;
		} else if (ArrayUtils.first(args).startsWith("[") && ArrayUtils.last(args).endsWith("]")) {
			IS_ENCLOSED_ARRAY.set(true);
			return InternalArgCopyAction.BREAK;
		} else {
			throw new UnexpectedObjectTypeError("Unknown object: " + args[i]);
		}
	}

	/*
	 * FIXME: Enclosed arrays still keep their original values after [0].
	 */
	public static void copyArguments(final String[] args, final Object[] output, final BaseJSFunction function) {
		final variable<Boolean> IS_ENCLOSED_ARRAY = new variable<Boolean>(false);
		for (int i = 0; i < output.length; i++) {
			String arg = args[i];
			final InternalArgCopyAction o = internalArgCopy(arg, i, IS_ENCLOSED_ARRAY, args, output, function);
			if (o == InternalArgCopyAction.BREAK)
				break;
			else if (o == InternalArgCopyAction.CONTINUE)
				continue;
		}
		if (IS_ENCLOSED_ARRAY.get()) {
			final Object[] arr = new Object[args.length];
			for (int i = 0; i < output.length; i++) {
				String arg = args[i];
				if (arg.startsWith("["))
					arg = arg.substring(1);
				if (arg.endsWith("]"))
					arg = arg.substring(0, arg.length() - 1);
				final InternalArgCopyAction o = internalArgCopy(arg, i, IS_ENCLOSED_ARRAY, args, output, function);
				if (o == InternalArgCopyAction.BREAK)
					throw new UnknownOperationError("copyArguments@IS_ENCLOSED_ARRAY: Cannot escape an already enclosed array!");
				else if (o == InternalArgCopyAction.CONTINUE)
					continue;
			}
			output[0] = arr;
		}
	}
}
